package com.tool.emulator.apple2;

import com.tool.emulator.apple2.runtime.EmuState;
import com.tool.emulator.apple2.ui.MonitorPane;
import com.tool.emulator.common.AccessUnit;
import com.tool.emulator.common.AutoDevice;
import com.tool.emulator.common.IODevice;

/**
 * Monitor.java @author tl 2011-6-18
 */
public class Monitor extends AutoDevice implements IODevice, Apple2Constants {
	public static final long FREQ = 60;
	public static final int TEXT_MODE = 1 << 0;
	public static final int MIXED_MODE = 1 << 1;
	public static final int PAGE2 = 1 << 2;
	public static final int HGR_MODE = 1 << 3;

	protected final Apple2 bus;
	protected transient volatile MonitorUI ui;
	protected volatile int mode = TEXT_MODE;

	public Monitor(Apple2 bus) {
		super("Monitor", FREQ);
		this.bus = bus;
		this.bus.BUS.initIO(Apple2.ADDR_IO_MONITOR, 8, this);
		this.setDefaultUI();
	}

	public MonitorUI setDefaultUI() {
		MonitorUI ui = new MonitorPane(bus);
		this.setUI(ui);
		return ui;
	}

	@Override
	public void deviceLoadState(EmuState emuState) throws Exception {
		super.deviceLoadState(emuState);
		MonitorUI ui = this.getUI();
		if (ui != null)
			ui.modeChanged(this);
	}

	public int getChar(int row, int col) {
		return bus.BUS.read(Util.getTextAddr(false, row) + col);
	}

	public boolean isBlank() {
		long cycles = this.getCycles();
		long freq = this.getFreq() / 2;
		return cycles % freq >= freq / 2;
	}

	public Apple2 getApple2() {
		return this.bus;
	}

	public int getDisplayMode() {
		return this.mode;
	}

	public void setDisplayMode(int mode) {
		this.mode = mode;
		MonitorUI ui = this.getUI();
		if (ui != null)
			ui.modeChanged(this);
	}

	public MonitorUI getUI() {
		return this.ui;
	}

	public void setUI(MonitorUI ui) {
		this.ui = ui;
	}

	public int read_io(int addr) {
		int mode0 = this.mode;
		int off = addr - Apple2.ADDR_IO_MONITOR;
		if (off >= 0 && off < 8) {
			if (0 != (off & 1))
				this.mode |= 1 << (off >>> 1);
			else
				this.mode &= ~(1 << (off >>> 1));
		}
		if (mode0 != this.mode) {
			MonitorUI ui = this.getUI();
			ui.modeChanged(this);
			//System.err.println("switch display mode " + off);
		}
		return mode & 0xff;
	}

	public void write_io(int addr, int val) {
		read_io(addr);
		read_io(addr);
	}

	@Override
	protected boolean deviceStep() {
		MonitorUI ui = this.getUI();
		if (ui != null)
			ui.refresh(this);
		this.current_cycles++;
		return true;
	}

	@Override
	protected void deviceInit() throws Exception {
		super.deviceInit();
		//clear screen
		this.cls();
		this.setText(11, 6, "APPLE][ EMULATOR");
		this.setText(12, 10, "WRITTEN BY TAOLEI 2011/6");

	}

	public void setText(int row, int col, int val) {
		this.getApple2().BUS.write(Util.getTextAddr(row) + col, val);
	}

	public void setText(int row, int col, String text) {
		for (int i = 0; i < text.length(); i++) {
			int c = text.charAt(i);
			c |= 0x80;
			setText(row, col, c);
			col++;
			if (col >= Apple2.TEXT_COLS) {
				row++;
				col = 0;
				if (row >= Apple2.TEXT_ROWS) {
					scroll();
					row--;
				}
			}
		}
	}

	public void cls() {
		for (int row = 0; row < Apple2.TEXT_ROWS; row++)
			clearRow(row);
	}

	public void scroll() {
		AccessUnit[] mem = this.getApple2().MEM;
		for (int row = 0; row < Apple2.TEXT_ROWS - 1; row++) {
			int addr = Util.getTextAddr(row);
			int addr1 = Util.getTextAddr(row + 1);
			for (int col = 0; col < Apple2.TEXT_COLS; col++)
				mem[addr + col].directSet(mem[addr1 + col].directGet());
		}
		clearRow(Apple2.TEXT_ROWS - 1);
	}

	public void clearRow(int row) {
		int addr = Util.getTextAddr(row);
		for (int col = 0; col < Apple2.TEXT_COLS; col++)
			this.getApple2().BUS.write(addr + col, 0xA0);
	}
}
